package com.arvato.common.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.arvato.common.redis.RedisUtil;
import com.arvato.common.util.ContantFinalUtil;
import com.arvato.common.util.JsonUtil;
import com.arvato.minipro.bean.bean_dto.common.Query;
import com.arvato.minipro.bean.bean_dto.common.Result;
import com.arvato.right.bean.bean_vo.WxworkRightPassVo;
import com.arvato.right.service.WxworkRightPassService;
import com.arvato.wxwork.bean.bean_do.other.WxworkOperateLogDo;
import com.arvato.wxwork.service.other.WxworkOperateLogService;
/**
 * 自定义过滤器 
 * 过滤器：过滤没有登录的请求转向到登录页
 * 拦截器：拦截没有权限的请求
 * 处理好登录 退出登录 还有那些链接免登录 还有那些链接需要跳转到登录页
 * @author ZHAN655
 */
public class LoginFilter implements Filter {

	@Autowired
	private RedisUtil redisUtil;

	@Autowired
	private JsonUtil jsonUtil;
	
	@Autowired
	private WxworkOperateLogService wxworkOperateLogService;
	
	@Autowired
	private WxworkRightPassService wxworkRightPassService;

	private static final Logger logger = LoggerFactory.getLogger(LoginFilter.class);
  
    @Override
    public void doFilter(ServletRequest servletReq, ServletResponse servletResp, FilterChain filterChain) throws IOException, ServletException {
    	HttpServletRequest req = (HttpServletRequest) servletReq;
        HttpServletResponse resp = (HttpServletResponse) servletResp;
        String url = req.getRequestURL().toString();
        String uri = req.getRequestURI();
        int a = 1;
        if(a == 1) {
        	filterChain.doFilter(req, resp);
        	return;
        }
        // 静态资源全部放行
        if(uri.contains(".") && !uri.endsWith("html")) {
        	filterChain.doFilter(req, resp);
			return;
        }
        // 访问public文件夹的或者是访问服务器ftp文件的 也都放行
        if(uri.startsWith(ContantFinalUtil.CONTEXT + "/public") || uri.startsWith(ContantFinalUtil.CONTEXT + "/img")) {
        	filterChain.doFilter(req, resp);
        	return;
        }
        getRealAddr(req);
        logger.info("请求的url" + url);
        logger.info("请求的uri" + uri);
        logger.info("ContantFinalUtil.CONTEXT:" + ContantFinalUtil.CONTEXT);
        // 企业微信的前台和后台请求都拦截住
        boolean pass = pass(uri);
        if(pass) {
        	logger.info("pass");
        	filterChain.doFilter(req, resp);
			return;
        }
        // 校验登录页
        if(uri.equals(ContantFinalUtil.CONTEXT + "/admin/login.html")) {
        	// 如过是登录请求 就检查是否已经登录过了 登录过了的话直接跳转index页
        	Cookie[] cookies = req.getCookies();
        	if(cookies != null && cookies.length != 0) {
        		for(Cookie cookie : cookies){
            		if(cookie.getName().equals("token")
        				&& redisUtil.get(cookie.getValue()) != null 
        				&& !redisUtil.get(cookie.getValue()).equals("")) {
            	        refreshToken(resp, cookie.getValue());
            			// 已经有了token的跳转到后台首页
                    	resp.setCharacterEncoding("UTF-8");
                    	resp.setHeader("Content-type", "text/html;charset=UTF-8");
                    	resp.sendRedirect(getRedirectAddr(req, ContantFinalUtil.CONTEXT + "/admin/index.html"));
                    	return;
            		}
            	}
        	}
        	filterChain.doFilter(req, resp);
    		return;
        }
        // 校验业务请求
        if(uri.startsWith(ContantFinalUtil.CONTEXT + "/admin") || uri.startsWith(ContantFinalUtil.CONTEXT + "/wxwork")) {
        	// 测试的时候 如果有这个参数 都放行(实在是因为企业微信坑太多)
        	String parameter = req.getParameter("arvato_test");
        	if(parameter != null && !parameter.equals("")) {
        		filterChain.doFilter(req, resp);
    			return;
        	}
        	// 前端小程序没有cookie 验证的是token
        	String token = req.getParameter("token");
        	if(token != null && redisUtil.get(token) != null && !redisUtil.get(token).equals("") ) {
    			redisUtil.set(token, redisUtil.get(token), 7200);
    			filterChain.doFilter(req, resp);
    			return;
        	}
        	// 后台验证的是cookie
        	Cookie[] cookies = req.getCookies();
        	if(cookies == null || cookies.length == 0) {
        		reject(req, resp);
        		return;
        	}
    		for(Cookie cookie : cookies){
        		if(cookie.getName().equals("token")
    				&& redisUtil.get(cookie.getValue()) != null 
    				&& !redisUtil.get(cookie.getValue()).equals("")) {
        			// 刷新token
        	        refreshToken(resp, cookie.getValue());
        	        // 记录管理员操作日志
        	        try {
						operateLog(req, redisUtil.get(cookie.getValue()));
					} catch (Exception e) {
						e.printStackTrace();
					}
        			filterChain.doFilter(req, resp);
        			return;
        		}
        	}
        }
        if(uri.startsWith(ContantFinalUtil.CONTEXT + "/mall") || uri.startsWith(ContantFinalUtil.CONTEXT + "/pubaccount")) {
        	filterChain.doFilter(req, resp);
        	return;
        }
        // 不符合我们要求的 我们全部跳转到登录页 或者提示登录
        reject(req, resp);
        return;
    }

	@Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
    /**
     * @Description: 是否需要过滤
     * @Date: 2018-03-12 13:20:54
     * @param uri
     */
    public boolean pass(String uri) {
    	List<String> passUrlList = getPassUrlList();
        if(passUrlList.contains(uri.toString())) {
        	return true;
        }
        return false;
    }
    
    
    /**
     * 拒绝掉当前请求
     * @param req
     * @param resp
     * @throws IOException
     */
    private void reject(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        logger.info("拒绝url：" + req.getRequestURL());
    	String XRequested = req.getHeader("X-Requested-With");
        if("XMLHttpRequest".equals(XRequested)){
        	// 若是ajax请求 返回没有登录的json
        	resp.setCharacterEncoding("UTF-8");
        	resp.setHeader("Content-type", "text/html;charset=UTF-8");
        	resp.getWriter().write(jsonUtil.obj2String(Result.fail("未登录的请求")));
        }else{
        	// 没有登录信息的 跳转到登录页
        	resp.setCharacterEncoding("UTF-8");
        	resp.setHeader("Content-type", "text/html;charset=UTF-8");
        	resp.sendRedirect(getRedirectAddr(req, ContantFinalUtil.CONTEXT + "/admin/login.html"));
        }
    }
    
    /**
     * 获取需要重定向的路径
     * @param request
     * @param uri
     * @return
     */
    private String getRedirectAddr(HttpServletRequest request, String uri) {
    	String url = request.getRequestURL().toString();
    	String serverName = request.getServerName();
    	int serverPort = request.getServerPort();
    	String protocol = "http://";
    	if(serverPort == 443 || url.startsWith("https")) {
    		protocol = "https://";
    	}
    	String redirectUrl = protocol + serverName + ":" + serverPort + uri;
    	logger.info("重定向url:" + redirectUrl);
    	return redirectUrl;
    }
    
    /**
     * 刷新token
     * @param resp
     * @param key
     */
    private void refreshToken(HttpServletResponse resp, String key) {
    	String value = redisUtil.get(key);
    	// 刷新token信息
		redisUtil.set(key, value, 7200);
		// 将token放在cookie里面返回去
        Cookie tokenCookie = new Cookie("token", key);
        // 如果不设置使用时间，那么将取不到Cookie的值
        tokenCookie.setMaxAge(3600 * 2);
        // 一旦设置了cookie的路径，就只能通过这一个路径才能获取到cookie信息
        tokenCookie.setPath("/");
        // 服务器把cookie响应给客户端，所有的cookie对象，都会在服务器端创建，通过http响应给客户端(浏览器)
        resp.addCookie(tokenCookie);
    }
    
    /**
     * 获取nginx代理后的真实IP
     * @param request
     */
    private void getRealAddr(HttpServletRequest request) {
    	StringBuffer url = request.getRequestURL();
    	System.out.println("url:" + url);
    	String serverName = request.getServerName();
    	logger.info("serverName = {}", serverName);
    	String ip = request.getHeader("x-forwarded-for");
        logger.info("x-forwarded-for = {}", ip);
       if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("Proxy-Client-IP"); 
           logger.info("Proxy-Client-IP = {}", ip); 
       }
       if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("WL-Proxy-Client-IP");
           logger.info("WL-Proxy-Client-IP = {}", ip);
       }
       if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getRemoteAddr();
           logger.info("RemoteAddr-IP = {}", ip); 
       }
    }
    
    /**
     * 记录用户操作日志
     * @param request
     * @param string 
     */
    private void operateLog(HttpServletRequest req, String string) {
    	String serverName = req.getServerName();
    	String ip = req.getHeader("x-forwarded-for") ;
    	if(ip != null) {
    		serverName += "{" + ip + "}";
    	}
    	Enumeration<?> enu = req.getParameterNames();
    	String param = "";
    	while(enu.hasMoreElements()){  
	    	String paraName=(String)enu.nextElement();  
	    	param += paraName+": "+req.getParameter(paraName);
    	}
    	Map<String, Object> str2Map = jsonUtil.str2Map(string);
    	String id = str2Map.get("userId") + "";
    	String name = str2Map.get("nickname") + "";
    	WxworkOperateLogDo logDo = new WxworkOperateLogDo();
    	logDo.setUrl(req.getRequestURI());
    	logDo.setId(id);
    	logDo.setName(name);
    	logDo.setDetail(param);
    	logDo.setCreateTime(new Date());
    	logDo.setIp(serverName);
    	wxworkOperateLogService.insert(logDo);
    }
    
    /**
     * 记录用户操作日志
     * @param request
     * @param string 
     */
    private List<String> getPassUrlList() {
    	Query query = new Query();
    	query.put("pageSize", 100);
    	List<WxworkRightPassVo> passList = wxworkRightPassService.listPassByQuery(query);
    	List<String> list = new ArrayList<String>();
    	for(WxworkRightPassVo passVo : passList) {
    		list.add(ContantFinalUtil.CONTEXT + passVo.getUrl());
    	}
    	return list;
    }
    
    
}